/**
 *    Copyright 2009-2021 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor.resultset;

import org.apache.ibatis.annotations.AutomapConstructor;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.cursor.defaults.DefaultCursor;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.loader.ResultLoader;
import org.apache.ibatis.executor.loader.ResultLoaderMap;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.result.DefaultResultContext;
import org.apache.ibatis.executor.result.DefaultResultHandler;
import org.apache.ibatis.executor.result.ResultMapException;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.Discriminator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.reflection.MetaClass;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.lang.reflect.Constructor;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

/**
 * @author Clinton Begin
 * @author Eduardo Macarron
 * @author Iwao AVE!
 * @author Kazuki Shimizu
 */
public class DefaultResultSetHandler implements ResultSetHandler {

	private static final Object DEFERRED = new Object();

	/** 执行器 */
	private final Executor executor;
	/** 全局配置信息 */
	private final Configuration configuration;
	/** SQL 节点 */
	private final MappedStatement mappedStatement;
	private final RowBounds rowBounds;
	/** 用户指定用于处理参数集的 ParameterHandler 对象 */
	private final ParameterHandler parameterHandler;
	/** 用户指定用于处理结果集的 ResultHandler 对象 */
	private final ResultHandler<?> resultHandler;
	/** 存储sql语句对象 */
	private final BoundSql boundSql;
	/** TypeHandler的注册中心 */
	private final TypeHandlerRegistry typeHandlerRegistry;
	/** 对象工厂 */
	private final ObjectFactory objectFactory;
	/** 反射工具 */
	private final ReflectorFactory reflectorFactory;

	// nested resultmaps
	/**
	 * 嵌套的Result
	 * <pre>
	 *     key：cacheKey 主结果就一个cacheKey
	 *     value:是result的结果集
	 * </pre>
	 */
	private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>();
	private final Map<String, Object> ancestorObjects = new HashMap<>();
	private Object previousRowValue;

	// multiple resultSets
	/**
	 * 记录指定属性对应的结果集名称
	 * <pre>
	 *     key: 属性(property)的值
	 *     value: 对应的ResultMapping
	 * </pre>
	 */
	private final Map<String, ResultMapping> nextResultMaps = new HashMap<>();
	private final Map<CacheKey, List<PendingRelation>> pendingRelations = new HashMap<>();

	// Cached Automappings
	/**
	 * 缓存 ResultMap 没有指定映射列的集合
	 * <pre>
	 *     key：ResultMap 的 ID
	 *     value：没有指定映射的集合
	 * </pre>
	 */
	private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();

	/**
	 * 记录是否使用构造器创建对象
	 * <pre>
	 *     temporary marking flag that indicate using constructor mapping (use field to reduce memory usage)
	 * </pre>
	 */
	private boolean useConstructorMappings;

	/**
	 * 记录当前结果对象相应的 MetaObject 和  parentMapping
	 */
	private static class PendingRelation {
		public MetaObject metaObject;
		public ResultMapping propertyMapping;
	}

	/**
	 * 记录没有指定映射的列
	 */
	private static class UnMappedColumnAutoMapping {
		/** 列名 */
		private final String column;
		/** pojo的属性 */
		private final String property;
		/** type处理类 */
		private final TypeHandler<?> typeHandler;
		private final boolean primitive;

		public UnMappedColumnAutoMapping(String column, String property, TypeHandler<?> typeHandler,
				boolean primitive) {
			this.column = column;
			this.property = property;
			this.typeHandler = typeHandler;
			this.primitive = primitive;
		}
	}

	public DefaultResultSetHandler(Executor executor, MappedStatement mappedStatement,
			ParameterHandler parameterHandler, ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) {
		this.executor = executor;
		this.configuration = mappedStatement.getConfiguration();
		this.mappedStatement = mappedStatement;
		this.rowBounds = rowBounds;
		this.parameterHandler = parameterHandler;
		this.boundSql = boundSql;
		this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
		this.objectFactory = configuration.getObjectFactory();
		this.reflectorFactory = configuration.getReflectorFactory();
		this.resultHandler = resultHandler;
	}

	//
	// HANDLE OUTPUT PARAMETER
	//

	/**
	 * 对存储过程中输出参数的相关处理
	 */
	@Override
	public void handleOutputParameters(CallableStatement cs) throws SQLException {
		// 获取用户传入的实际参数，并为其创建相应的 MetaObject 对象
		final Object parameterObject = parameterHandler.getParameterObject();
		final MetaObject metaParam = configuration.newMetaObject(parameterObject);
		// 获取 BoundSql.parameterMapping 集合，其中记录了参数相关信息
		final List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		// 遍历所有参数信息
		for (int i = 0; i < parameterMappings.size(); i++) {
			final ParameterMapping parameterMapping = parameterMappings.get(i);
			if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {
				// 如果存在输出类型的参数，则解析参数值，并设置打 parameterObject 中
				if (ResultSet.class.equals(parameterMapping.getJavaType())) {
					// 如果指定该输出参数为 ResultSet 类型，则需要进行映射
					handleRefCursorOutputParameter((ResultSet) cs.getObject(i + 1), parameterMapping, metaParam);
				} else {
					// 使用 TypeHandler 获取参数值，并设置到 parameterObject 中
					final TypeHandler<?> typeHandler = parameterMapping.getTypeHandler();
					metaParam.setValue(parameterMapping.getProperty(), typeHandler.getResult(cs, i + 1));
				}
			}
		}
	}

	/**
	 * 负责处理 ResultSet 类型的输出参数
	 * <pre>
	 *     按照指定的 ResultSet 对该 ResultSet 类型的输出参数进行映射，
	 *     并将映射得到的结果对象设置到用户传入的 parameterObject 对象中。
	 * </pre>
	 * @param rs
	 * @param parameterMapping
	 * @param metaParam
	 * @throws SQLException
	 */
	private void handleRefCursorOutputParameter(ResultSet rs, ParameterMapping parameterMapping, MetaObject metaParam)
			throws SQLException {
		if (rs == null) {
			return;
		}
		try {
			// 获取映射使用的 ResultMap 对象
			final String resultMapId = parameterMapping.getResultMapId();
			final ResultMap resultMap = configuration.getResultMap(resultMapId);
			// 将结果集封装成 ResultSetWrapper
			final ResultSetWrapper rsw = new ResultSetWrapper(rs, configuration);
			if (this.resultHandler == null) {
				// 创建用于保存映射结果对象的 DefaultResultHandler 对象
				final DefaultResultHandler resultHandler = new DefaultResultHandler(objectFactory);
				// 通过 handleRowValues() 方法完成映射操作，并将结果存储到 DefaultResultHandler 中
				handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
				// 将映射得到的结果对象保存到 parameteObject 中
				metaParam.setValue(parameterMapping.getProperty(), resultHandler.getResultList());
			} else {
				handleRowValues(rsw, resultMap, resultHandler, new RowBounds(), null);
			}
		} finally {
			// issue #228 (close resultsets)
			closeResultSet(rs);
		}
	}

	//
	// HANDLE RESULT SETS
	//

	/**
	 * 处理查询数据库返回的结果集
	 * <pre>
	 *     通过 select 语句查询数据库得到的结果集由 handleResultSets() 方法处理。
	 *     该方法不仅可以处理 Statement、PreparedStatement 产生的结果集，
	 *     还可以处理 CallableStatement 调用存储过程产生的多结果集。
	 * </pre>
	 * @param stmt Statement
	 */
	@Override
	public List<Object> handleResultSets(Statement stmt) throws SQLException {
		ErrorContext.instance().activity("handling results").object(mappedStatement.getId());

		// <select>标签的 resultMap 属性，可以指定多个值，多个值之间用逗号（,）分割
		final List<Object> multipleResults = new ArrayList<>();

		int resultSetCount = 0;
		// 这里是获取第一个结果集，将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象
		ResultSetWrapper rsw = getFirstResultSet(stmt);

		// 这里是获取所有要映射的ResultMap（按照逗号分割出来的）
		List<ResultMap> resultMaps = mappedStatement.getResultMaps();
		// 要映射的ResultMap的数量
		int resultMapCount = resultMaps.size();
		validateResultMapsCount(rsw, resultMapCount);
		// --(1)
		// 循环处理每个ResultMap，从第一个开始处理
		while (rsw != null && resultMapCount > resultSetCount) {
			// 得到结果映射信息
			ResultMap resultMap = resultMaps.get(resultSetCount);
			// 处理结果集
			// 从rsw结果集参数中获取查询结果，再根据resultMap映射信息，将查询结果映射到multipleResults中
			handleResultSet(rsw, resultMap, multipleResults, null);
			// 获取下一个结果集
			rsw = getNextResultSet(stmt);
			// 清空 nestedResultObjects 集合
			cleanUpAfterHandlingResultSet();
			// 递增 resultSetCount
			resultSetCount++;
		}

		// 对应<select>标签的 resultSet 属性，（一般不使用该属性）
		// 该属性列出了多结果集的所有名称，名称之间用逗号分隔
		String[] resultSets = mappedStatement.getResultSets();
		if (resultSets != null) {
			// --(2)
			while (rsw != null && resultSetCount < resultSets.length) {
				// 根据 resultSets 的名称，获取未处理的 ResultMapping
				ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
				if (parentMapping != null) {
					// 获取映射该结果集要使用的 ResultMap 对象
					String nestedResultMapId = parentMapping.getNestedResultMapId();
					ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
					// 根据 ResultMap 对象映射结果集
					handleResultSet(rsw, resultMap, null, parentMapping);
				}
				// 获取下一个结果集
				rsw = getNextResultSet(stmt);
				// 清空 nestedResultObjects 集合
				cleanUpAfterHandlingResultSet();
				// 递增 resultSetCount
				resultSetCount++;
			}
		}

		// 如果只有一个结果集合，则直接从多结果集中取出第一个
		return collapseSingleResultList(multipleResults);
	}

	/**
	 * 该方法在数据库查询结束之后，将结果集对应的 ResultSetWrapper 对象
	 * 以及映射使用的 ResultMap 对象封装成 DefaultCursor 对象并返回
	 * @param stmt JDBC封装的 Statement
	 * @return DefaultCursor
	 * @throws SQLException
	 */
	@Override
	public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException {
		ErrorContext.instance().activity("handling cursor results").object(mappedStatement.getId());
		// 获取结果集并封装成 ResultSetWrapper 对象
		ResultSetWrapper rsw = getFirstResultSet(stmt);
		// 获取映射使用的 ResultMap 对象集合
		List<ResultMap> resultMaps = mappedStatement.getResultMaps();

		// 边界检测，只能映射一个结果集，所以只能存在一个 ResultMap 对象
		int resultMapCount = resultMaps.size();
		validateResultMapsCount(rsw, resultMapCount);
		if (resultMapCount != 1) {
			throw new ExecutorException("Cursor results cannot be mapped to multiple resultMaps");
		}

		ResultMap resultMap = resultMaps.get(0);
		// 将 ResultSetWrapper 对象、映射使用的 ResultMap 对象
		// 以及控制映射的起止位置的 RowBounds 对象封装成 DefaultCursor
		return new DefaultCursor<>(this, resultMap, rsw, rowBounds);
	}

	/**
	 * 获取第一个 ResultSet 对象，并封装成 ResultSetWrapper
	 * <pre>
	 *     stmt 可能存在多个 ResultSet，但这里只获取第一个 ResultSet。
	 * </pre>
	 * @param stmt jdbc 的 Statement
	 * @return ResultSetWrapper
	 */
	private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {
		ResultSet rs = stmt.getResultSet();
		while (rs == null) {
			// move forward to get the first resultset in case the driver
			// doesn't return the resultset as the first result (HSQLDB 2.1)
			// 检测是否还有待处理的 ResultSet
			if (stmt.getMoreResults()) {
				rs = stmt.getResultSet();
			} else {
				if (stmt.getUpdateCount() == -1) {
					// 没有待处理的 ResultSet
					// no more results. Must be no resultset
					break;
				}
			}
		}
		// 将结果封装成 ResultSetWrapper 对象
		return rs != null ? new ResultSetWrapper(rs, configuration) : null;
	}

	/**
	 * 获取下一个结果集
	 */
	private ResultSetWrapper getNextResultSet(Statement stmt) {
		// Making this method tolerant of bad JDBC drivers
		try {
			// 检测 JDBC 是否支持多结果集
			if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {
				// Crazy Standard JDBC way of determining if there are more results
				// 检测是否还要待处理的结果集，若存在，则封装成 ResultSetWrapper 对象并返回
				if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {
					ResultSet rs = stmt.getResultSet();
					if (rs == null) {
						return getNextResultSet(stmt);
					} else {
						return new ResultSetWrapper(rs, configuration);
					}
				}
			}
		} catch (Exception e) {
			// Intentionally ignored.
		}
		return null;
	}

	/**
	 *  调用 ResultSet.close() 方法关闭结果集
	 */
	private void closeResultSet(ResultSet rs) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			// ignore
		}
	}

	/**
	 * 清空 nestedResultObjects 集合
	 */
	private void cleanUpAfterHandlingResultSet() {
		nestedResultObjects.clear();
	}

	/**
	 * 校验“ResultMaps”的数量
	 */
	private void validateResultMapsCount(ResultSetWrapper rsw, int resultMapCount) {
		if (rsw != null && resultMapCount < 1) {
			throw new ExecutorException(
					"A query was run and no Result Maps were found for the Mapped Statement '" + mappedStatement.getId()
							+ "'.  It's likely that neither a Result Type nor a Result Map was specified.");
		}
	}

	/**
	 * 完成对单个 ResultSet/ResultMap 进行映射
	 * <pre>
	 *     根据 ResultMap 中定义的映射规则对 ResultSet 进行映射，并将映射的结果对象添加到 multipleResults
	 * </pre>
	 * @param rsw 数据库查询出结果
	 * @param resultMap 当个ResultMap/ResultSet
	 * @param multipleResults 存储查询结果
	 * @param parentMapping 未处理的 ResultMapping
	 */
	private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults,
			ResultMapping parentMapping) throws SQLException {
		try {
			// 处理嵌套结果映射
			if (parentMapping != null) {
				// 处理多个结果集中的嵌套映射
				handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);
			} else {
				// 第一次一般来说resultHandler为空，则创建DefaultResultHandler来处理结果
				if (resultHandler == null) {
					DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);
					// 对 Result 进行映射到 defaultResultHandler
					handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);
					// 将映射得到的结果对象添加到 multipleResults 集合中
					multipleResults.add(defaultResultHandler.getResultList());
				} else {
					// 使用用户指定的 ResultHandler 对象处理结果对象
					handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);
				}
			}
		} finally {
			// issue #228 (close resultsets)
			// 调用 ResultSet.close() 方法关闭结果集
			closeResultSet(rsw.getResultSet());
		}
	}

	@SuppressWarnings("unchecked")
	private List<Object> collapseSingleResultList(List<Object> multipleResults) {
		return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults;
	}

	//
	// HANDLE ROWS FOR SIMPLE RESULTMAP
	//

	/**
	 * 对 Result 进行映射到 resultHandler
	 * <pre>
	 *     映射结果集的核心代码，其中有两个分支
	 *     第1分支：针对包含嵌套映射的处理
	 *     第2分支：针对不含嵌套映射的简单映射的处理
	 * </pre>
	 * @param rsw 数据库查询出结果
	 * @param resultMap select 节点的 resultMap 属性
	 * @param resultHandler 用户指定用于处理结果集的 ResultHandler 对象
	 * @param rowBounds 内存分页
	 * @param parentMapping 未处理的 ResultMapping
	 */
	public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler,
			RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
		// 是否有内置嵌套的结果映射
		if (resultMap.hasNestedResultMaps()) {
			// 第1分支：针对存在嵌套 ResultMap 的情况
			// 检测是否运行在嵌套映射中使用 RowBounds
			ensureNoRowBounds();
			// 检测是否运行在嵌套映射中使用用户自定义的 ResultHandler
			checkResultHandler();
			// 嵌套结果映射
			handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
		} else {
			// 第2分支：针对不含嵌套映射的处理（简单结果映射）
			handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
		}
	}

	/**
	 * 检测是否运行在嵌套映射中使用 RowBounds
	 * @throws ExecutorException 抛出异常表示不允许 RowBounds 分页操作
	 */
	private void ensureNoRowBounds() {
		if (configuration.isSafeRowBoundsEnabled() && rowBounds != null
				&& (rowBounds.getLimit() < RowBounds.NO_ROW_LIMIT || rowBounds.getOffset() > RowBounds.NO_ROW_OFFSET)) {
			throw new ExecutorException(
					"Mapped Statements with nested result mappings cannot be safely constrained by RowBounds. "
							+ "Use safeRowBoundsEnabled=false setting to bypass this check.");
		}
	}

	/**
	 * 检测是否运行在嵌套映射中使用用户自定义的 ResultHandler
	 * @throws ExecutorException 抛出异常表示不允许用户自定义 ResultHandler
	 */
	protected void checkResultHandler() {
		if (resultHandler != null && configuration.isSafeResultHandlerEnabled() && !mappedStatement.isResultOrdered()) {
			throw new ExecutorException(
					"Mapped Statements with nested result mappings cannot be safely used with a custom ResultHandler. "
							+ "Use safeResultHandlerEnabled=false setting to bypass this check "
							+ "or ensure your statement returns ordered data and set resultOrdered=true on it.");
		}
	}

	/**
	 * 针对不含嵌套映射的处理（简单结果映射）
	 * <pre>
	 *     1. 调用 skipRows() 方法，根据 RowBounds 中的 offset 值定位到指定的记录行
	 *     2. 调用 shouldProcessMoreRows() 方法，检测是否还有需要映射的记录
	 *     3. 通过 resolveDiscriminatedResultMap() 方法，确定映射使用的 ResultMap 对象
	 *     4. 调用 getRowValue() 方法对 ResultSet 中的一行记录进行映射：
	 *     		a. 通过 createResultObject() 方法创建映射后的结果对象
	 *     	 	b. 通过 shouldApplyAutomaticMappings() 方法判断是否开启了自动映射功能。
	 *     	 	c. 通过 applyAutomaticMappings() 方法自动映射 ResultMap 中未明确映射的列
	 *     	 	d. 通过 applyPropertyMapping() 方法映射ResultMap 中明确映射列
	 *     	 	到这里该行记录的数据以及完全映射到结果对象的相应属性中
	 *     5. 调用 storeObject()方法保存映射得到的结果对象
	 * </pre>
	 */
	private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap,
			ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
		DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
		// 获取结果集信息
		ResultSet resultSet = rsw.getResultSet();
		// 步骤1：使用rowBounds的分页信息，进行逻辑分页（也就是在内存中分页）
		skipRows(resultSet, rowBounds);
		// 步骤2：检测已经处理的行数是否已经达到上限（RowBounds.limit)以及 ResultSet 中是否还有可处理的记录
		while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
			// 步骤3：通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别
			ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
			// 步骤4：将查询结果封装到POJO中
			Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
			// 步骤5：处理对象嵌套的映射关系（将映射创建的结果对象添加到 ResultHandler.resultList 中保存）
			storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
		}
	}

	/**
	 * 将结果(rowValue)对象保存到合适的位置
	 * @param resultHandler
	 * @param resultContext
	 * @param rowValue 结果
	 * @param parentMapping
	 * @param rs JDBC封装的ResultSet
	 * @throws SQLException
	 */
	private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
			Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {
		if (parentMapping != null) {
			// 嵌套查询或嵌套映射，将结果对象保存到父对象对应的属性中
			linkToParents(rs, parentMapping, rowValue);
		} else {
			// 普通映射，将结果对象保存到 ResultHandler 中
			callResultHandler(resultHandler, resultContext, rowValue);
		}
	}


	/**
	 * 普通映射，将结果对象保存到 ResultHandler 中
	 * @param resultHandler 保存结果对象的集合
	 * @param resultContext result上下文
	 * @param rowValue 行结果(POJO对象)
	 */
	@SuppressWarnings("unchecked" /* because ResultHandler<?> is always ResultHandler<Object> */)
	private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext,
			Object rowValue) {
		// 递增 DefaultResultContext.resultObject 该值用于检测处理的记录行数是否已经达到上限(在 RowBounds.limit 字段中记录了该上限)。
		// 之后将结果对象保存到  DefaultResultContext.resultObject 字段中
		resultContext.nextResultObject(rowValue);
		// 将结果对象添加到 ResultHandler.resultList 中保存
		((ResultHandler<Object>) resultHandler).handleResult(resultContext);
	}

	/**
	 * 检测是否能够对后续的记录进行映射操作
	 */
	private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {
		// 1. 检测 DefaultResultContext.stopped 字段
		// 2. 检测映射行数是否达到 RowBounds.limit 的限制
		return !context.isStopped() && context.getResultCount() < rowBounds.getLimit();
	}

	/**
	 * 根据 RowBounds.offset 字段的值定位到指定的记录（内存中分页）
	 * @param rs 数据库结果
	 * @param rowBounds 分页
	 */
	private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {
		// 根据 ResultSet 的类型进行定位
		if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
			if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {
				// 直接定位到 offset 指定的记录
				rs.absolute(rowBounds.getOffset());
			}
		} else {
			// 通过多次调用 ResultSet.next() 方法移动到指定的记录
			for (int i = 0; i < rowBounds.getOffset(); i++) {
				if (!rs.next()) {
					break;
				}
			}
		}
	}

	//
	// GET VALUE FROM ROW FOR SIMPLE RESULT MAP
	//

	/**
	 * 将查询结果封装到POJO中
	 * <pre>
	 *     1. 根据 ResultMap 指定的类型创建对应的结果对象，以及对应的 MetaObject 对象。
	 *     2. 根据配置信息，决定是否自动映射 ResultMap 中未明确映射的列
	 *     3. 根据 ResultMap 映射明确指定的属性和列。
	 *     4. 返回映射得到的结果对象
	 * </pre>
	 * @param rsw JDBC的 ResultSet 封装类
	 * @param resultMap 最终使用的 ResultMap 对象
	 * @param columnPrefix 列前缀
	 * @return 映射的PO类对象
	 */
	private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
		// 延迟加载的映射信息
		final ResultLoaderMap lazyLoader = new ResultLoaderMap();
		// 创建要映射的PO类对象
		// 步骤1：创建该行记录映射之后得到的结果对象，该结果对象的类型由 <resultMap> 节点的 type 属性指定
		Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
		if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
			// 创建上述结果对象相应的 MetaObject 对象
			final MetaObject metaObject = configuration.newMetaObject(rowValue);
			// 成功映射任意属性，则 foundValues 为 true,否则 foundValues 为 false
			boolean foundValues = this.useConstructorMappings;
			// 检测是否应用自动映射，也就是通过resultType进行映射
			if (shouldApplyAutomaticMappings(resultMap, false)) {
				// 步骤2：自动映射(自动映射 ResultMap 中未明确指定的列)，根据columnName和type属性名映射赋值
				foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
			}
			// 步骤3：根据我们配置ResultMap的column和property映射赋值
			// 如果映射存在nestedQueryId，会调用getNestedQueryMappingValue方法获取返回值
			foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
			foundValues = lazyLoader.size() > 0 || foundValues;
			// 步骤4：如果没有成功映射任何属性，则根据 mybatis-config.xml中的 <returnInstanceForEmptyRow> 配置决定返回空的结果，还是返回 null
			rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
		}
		return rowValue;
	}

	/**
	 * 检测是否开启自动映射
	 * <pre>
	 *     1. 在 ResultMap 节点中明确配置了 autoMapping 属性，则优先根据该属性的值决定是否开启自动映射功能
	 *     2. 如果没有配置 autoMapping 属性，则根据 mybatis-config.xml 中 settings 节点中配置 autoMappingBehavior 值
	 *         (默认值：PARTIAL)决定是否开启自动映射功能。
	 *         autoMappingBehavior 值
	 *         		PARTIAL：只会自动映射没有定义嵌套映射的 ResultSet
	 *         		NONE：取消自动映射
	 *         		FULL：会自动映射任意复杂的ResultSet(无法是否嵌套)
	 * </pre>
	 * @param resultMap ResultMap 节点
	 * @param isNested 是否为“嵌套查询”或“嵌套映射”
	 * @return true-自动映射；false-取消自动映射
	 */
	private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {
		// 获取 resultMap 中的 autoMapping 属性值
		if (resultMap.getAutoMapping() != null) {
			return resultMap.getAutoMapping();
		} else {
			// 检测是否为“嵌套查询”或“嵌套映射”
			if (isNested) {
				// 是“嵌套查询”或“嵌套映射”
				return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();
			} else {
				return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();
			}
		}
	}

	//
	// PROPERTY MAPPINGS
	//

	/**
	 * 处理 ResultMap 中明确需要进行映射的列
	 * <pre>
	 *     存在三种场景
	 *     	场景1：column 是“{prop1=col1,prop2=col2}”这种形式的，一般与嵌套查询配合使用，
	 *     		 表示将 col1 和 col2 的列值传递给内层嵌套查询作为参数
	 *     	场景2：基本类型的属性映射
	 *     	场景3：多结果集的场景处理，该属性类另一个结果集
	 * </pre>
	 * @param rsw JDBC的 ResultSet 封装类
	 * @param resultMap 最终使用的 ResultMap 对象
	 * @param metaObject PO实体类
	 * @param lazyLoader 添加延迟加载的对象
	 * @param columnPrefix 列前缀
	 * @return
	 * @throws SQLException
	 */
	private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
			ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
		// 获取该 ResultMap 中明确需要进行映射的列名集合
		final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
		boolean foundValues = false;
		// 获取 ResultMap.propertyResultMappings 集合，其中记录了映射使用的所有 ResultMapping 对象
		final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
		for (ResultMapping propertyMapping : propertyMappings) {
			// 处理列前缀
			String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
			if (propertyMapping.getNestedResultMapId() != null) {
				// the user added a column attribute to a nested result map, ignore it
				// 该属性需要使用一个嵌套 ResultMap 进行映射，忽略 column 属性
				column = null;
			}
			// 	场景1：column 是“{prop1=col1,prop2=col2}”这种形式的，一般与嵌套查询配合使用，
			//	  		表示将 col1 和 col2 的列值传递给内层嵌套查询作为参数
			//	 场景2：基本类型的属性映射
			//	 场景3：多结果集的场景处理，该属性类另一个结果集
			if (propertyMapping.isCompositeResult() // ---场景1
					|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) // ---场景2
					|| propertyMapping.getResultSet() != null) // ---场景3
			{
				// 通过 getPropertyMappingValue() 方法完成映射，并得到属性值
				Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader,
						columnPrefix);
				// issue #541 make property optional
				// 获取属性名称
				final String property = propertyMapping.getProperty();
				if (property == null) {
					continue;
				} else if (value == DEFERRED) {
					// DEFERRED 表示的是占位符对象，
					foundValues = true;
					continue;
				}
				if (value != null) {
					foundValues = true;
				}
				if (value != null || (configuration.isCallSettersOnNulls()
						&& !metaObject.getSetterType(property).isPrimitive())) {
					// gcode issue #377, call setter on nulls (value is not 'found')
					// 设置属性值
					metaObject.setValue(property, value);
				}
			}
		}
		return foundValues;
	}

	/**
	 * 完成映射，并得到属性值
	 * @param rs JDBC的 ResultSet
	 * @param metaResultObject POJO实体类
	 * @param propertyMapping ResultMap 的 result/id 等
	 * @param lazyLoader
	 * @param columnPrefix 列前缀
	 * @return 属性值
	 */
	private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping,
			ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
		if (propertyMapping.getNestedQueryId() != null) {
			// 嵌套查询
			return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);
		} else if (propertyMapping.getResultSet() != null) {
			// 多结果集处理
			addPendingChildRelation(rs, metaResultObject, propertyMapping); // TODO is that OK?
			return DEFERRED;
		} else {
			// 获取 ResultMapping 中记录的 TypeHandler 对象
			final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();
			final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
			// 使用 TypeHandler 对象获取属性值
			return typeHandler.getResult(rs, column);
		}
	}

	/**
	 * 获取没有指定映射列的集合
	 * <pre>
	 *     为未映射的列查找对应的属性，并将两者关联起来封装成 UnMappedColumnAutoMapping
	 *     该方法产生的 UnMappedColumnAutoMapping 对象集合会缓存在 DefaultResultSetHandler.autoMappingsCache 字段中
	 *     key：ResultMap的 id 与 列前缀构成
	 * </pre>
	 * @param rsw JDBC的 ResultSet 封装类
	 * @param resultMap 最终使用的 ResultMap 对象
	 * @param metaObject PO实体类
	 * @param columnPrefix 列前缀
	 * @return
	 * @throws SQLException
	 */
	private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap,
			MetaObject metaObject, String columnPrefix) throws SQLException {
		// 自动映射的缓存 key
		final String mapKey = resultMap.getId() + ":" + columnPrefix;
		List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
		// 是否命中 autoMappingsCache 缓存
		if (autoMapping == null) {
			// autoMappingsCache 缓存未命中
			autoMapping = new ArrayList<>();
			// 从 ResultSetWrapper 中获取未映射的列名集合
			final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
			for (String columnName : unmappedColumnNames) {
				// 生成属性名称
				String propertyName = columnName;
				if (columnPrefix != null && !columnPrefix.isEmpty()) {
					if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
						//列名以前缀开头，则属性名称为列名去除前缀删除的部分
						propertyName = columnName.substring(columnPrefix.length());
					} else {
						continue;
					}
				}
				// 在结果对象中查找指定的属性名
				final String property = metaObject.findProperty(propertyName,
						configuration.isMapUnderscoreToCamelCase());
				// 检测是否存在该属性的 setter 方法，(注意：如果是MapWrapper,一直返回 true)
				if (property != null && metaObject.hasSetter(property)) {
					if (resultMap.getMappedProperties().contains(property)) {
						continue;
					}
					final Class<?> propertyType = metaObject.getSetterType(property);
					if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
						// 查找对应的 TypeHandler 对象
						final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
						// 创建 UnMappedColumnAutoMapping 对象，并添加到 autoMapping 集合中
						autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler,
								propertyType.isPrimitive()));
					} else {
						// 输出日志 或 抛出异常
						configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName,
								property, propertyType);
					}
				} else {
					// 输出日志 或 抛出异常
					configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName,
							(property != null) ? property : propertyName, null);
				}
			}
			// 将 autoMappingsCache 添加到缓存中保存
			autoMappingsCache.put(mapKey, autoMapping);
		}
		return autoMapping;
	}

	/**
	 * 自动映射
	 * <pre>
	 *     负责自动映射 ResultMap 中未明确映射的列
	 * </pre>
	 * @param rsw JDBC的 ResultSet 封装类
	 * @param resultMap 最终使用的 ResultMap 对象
	 * @param metaObject PO实体类
	 * @param columnPrefix 前缀
	 * @return
	 * @throws SQLException
	 */
	private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
			String columnPrefix) throws SQLException {
		// 获取没有指定映射列的集合
		List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
		boolean foundValues = false;
		if (!autoMapping.isEmpty()) {
			for (UnMappedColumnAutoMapping mapping : autoMapping) {
				// 使用 TypeHandler 获取自动映射的列值
				final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
				// 边界检测，更新 foundValues 值
				if (value != null) {
					foundValues = true;
				}
				if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
					// 将自动映射的属性值设置到结果对象中
					metaObject.setValue(mapping.property, value);
				}
			}
		}
		return foundValues;
	}

	// MULTIPLE RESULT SETS

	/**
	 * 嵌套查询或嵌套映射，将结果对象保存到父对象对应的属性中
	 * @param rs JDBC的ResultSet
	 * @param parentMapping 对应的 result 节点信息
	 * @param rowValue 嵌套对象
	 */
	private void linkToParents(ResultSet rs, ResultMapping parentMapping, Object rowValue) throws SQLException {
		// 创建 CacheKey 对象
		// 注意：这里构成 CacheKey 的第三部分，它换成了外键的值
		CacheKey parentKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
				parentMapping.getForeignColumn());
		// 获取 pendingRelations 集合中 parentKey 对应的 PendingRelation 对象
		List<PendingRelation> parents = pendingRelations.get(parentKey);
		if (parents != null) {
			// 遍历 pendingRelations 集合
			for (PendingRelation parent : parents) {
				if (parent != null && rowValue != null) {
					// 将当前记录的结果对象添加到外层对象的相应属性中
					linkObjects(parent.metaObject, parent.propertyMapping, rowValue);
				}
			}
		}
	}

	/**
	 * 对多结果集的情况进行处理
	 * @param rs JDBC封装的 ResultSet
	 * @param metaResultObject 目标结果的MetaObject
	 * @param parentMapping 对应的 result 节点信息
	 */
	private void addPendingChildRelation(ResultSet rs, MetaObject metaResultObject, ResultMapping parentMapping)
			throws SQLException {
		// 步骤1：为指定结果集创建 CacheKey 对象
		CacheKey cacheKey = createKeyForMultipleResults(rs, parentMapping, parentMapping.getColumn(),
				parentMapping.getColumn());
		// 步骤2：创建 PendingRelation 对象
		PendingRelation deferLoad = new PendingRelation();
		deferLoad.metaObject = metaResultObject;
		deferLoad.propertyMapping = parentMapping;
		// 步骤3：将 PendingRelation 对象添加到 pendingRelations
		List<PendingRelation> relations = pendingRelations.computeIfAbsent(cacheKey, k -> new ArrayList<>());
		// issue #255
		relations.add(deferLoad);
		// 步骤4：在 nextResultMaps 集合记录指定属性对应的结果集名称以及对应的 parentMapping
		ResultMapping previous = nextResultMaps.get(parentMapping.getResultSet());
		if (previous == null) {
			nextResultMaps.put(parentMapping.getResultSet(), parentMapping);
		} else {
			if (!previous.equals(parentMapping)) {
				throw new ExecutorException("Two different properties are mapped to the same resultSet");
			}
		}
	}

	/**
	 * 为指定结果集创建 CacheKey 对象
	 * <pre>
	 *     该 CacheKey 对象由三部分构成
	 *     		a) parentMapping 对象。
	 *     		b) parentMapping.column 属性指定的列名(可能有多个列)
	 *     		c) 这些列名在该记录中的值(可能有多个列)
	 * </pre>
	 * @param rs JDBC封装的 ResultSet
	 * @param resultMapping 对应的 result 节点信息
	 * @param names 属性信息(可能有多个列)
	 * @param columns 列名(可能有多个列)
	 * @return
	 * @throws SQLException
	 */
	private CacheKey createKeyForMultipleResults(ResultSet rs, ResultMapping resultMapping, String names,
			String columns) throws SQLException {
		CacheKey cacheKey = new CacheKey();
		cacheKey.update(resultMapping);
		if (columns != null && names != null) {
			String[] columnsArray = columns.split(",");
			String[] namesArray = names.split(",");
			for (int i = 0; i < columnsArray.length; i++) {
				// 查询该行记录对应列的值
				Object value = rs.getString(columnsArray[i]);
				if (value != null) {
					cacheKey.update(namesArray[i]);
					cacheKey.update(value);
				}
			}
		}
		return cacheKey;
	}

	//
	// INSTANTIATION & CONSTRUCTOR MAPPING
	//

	/**
	 * 创建要映射的PO类对象
	 * <pre>
	 *     根据结果集的列数，ResultMap.constructorResultMappings 集合等信息，选择不同方式的创建结果对象
	 * </pre>
	 * @param rsw JDBC的ResultSet封装类
	 * @param resultMap 最终的 ResultMap
	 * @param lazyLoader 延迟加载
	 * @param columnPrefix 列前缀
	 * @return POJO
	 */
	private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader,
			String columnPrefix) throws SQLException {
		// 标识是否使用构造函数创建该结果对象
		this.useConstructorMappings = false; // reset previous mapping result
		// 记录构造函数的参数类型
		final List<Class<?>> constructorArgTypes = new ArrayList<>();
		// 记录构造函数的实参
		final List<Object> constructorArgs = new ArrayList<>();
		// 创建结果映射的PO类对象(该方法是该步骤的核心)
		Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
		if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
			// 获取要映射的PO类的属性信息
			final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
			for (ResultMapping propertyMapping : propertyMappings) {
				// issue gcode #109 && issue #149
				// 如果包含嵌套查询，且配置了延迟加载，则使用ProxyFactory创建代理对象。(默认使用的是 JavassistProxyFactory)
				// 延迟加载处理
				if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
					// 通过动态代理工厂，创建延迟加载的代理对象(默认使用的是 JavassistProxyFactory)
					resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration,
							objectFactory, constructorArgTypes, constructorArgs);
					break;
				}
			}
		}
		// 记录是否使用构造器创建对象
		this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping
																								// result
		return resultObject;
	}

	/**
	 * 创建结果映射的PO类对象
	 * @param rsw myBatis封装JDBC的reusltSet
	 * @param resultMap 该 resultMap 节点信息
	 * @param constructorArgTypes 记录构造参数的类型集合
	 * @param constructorArgs 记录构造参数的实参
	 * @param columnPrefix 列前缀
	 * @return resultMap的 type 实体类
	 */
	private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,
			List<Object> constructorArgs, String columnPrefix) throws SQLException {
		// 获取 ResultMap 中记录的 type 属性，也就是该行记录最终映射成的结果对象类型
		final Class<?> resultType = resultMap.getType();
		// 创建该类型对应的 MetaClass 对象
		final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
		// 获取 ResultMap 中记录的 <constructor> 节点信息，如果该集合不为空，则可以通过该集合确定相应 Java 类中的唯一构造函数
		final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
		// 创建结果对象分下面 4 种场景
		if (hasTypeHandlerForResultObject(rsw, resultType)) {
			// 场景1：结果集只有一列，且存在 TypeHandler 对象可以将该列转换成 resultType 类型的值
			// 先查找相应的 TypeHandler 对象，再使用 TypeHandler 对象将该记录转换成 Java 类型的值
			return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
		} else if (!constructorMappings.isEmpty()) {
			// 场景2：ResultMap 中记录了 <constructor> 节点的信息
			// 通过反射方式调用构造方法，创建结果对象
			return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes,
					constructorArgs, columnPrefix);
		} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
			// 场景3：使用默认的无参构造函数
			// 直接使用 对象工厂(ObjectFactory) 创建对象
			return objectFactory.create(resultType);
		} else
			// 检测是否开启自动映射
			if (shouldApplyAutomaticMappings(resultMap, false)) {
			// 场景4：通过自动映射的方式查找合适的构造方法并创建结果对象
			return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix);
		}
		throw new ExecutorException("Do not know how to create an instance of " + resultType);
	}

	/**
	 * 场景2：ResultMap 中记录了 <constructor> 节点的信息
	 * @param rsw JDBC 封装的 ResultSet
	 * @param resultType 返回的类型
	 * @param constructorMappings constructor 节点信息的 idArg/arg(result) 信息
	 * @param constructorArgTypes 记录构造参数类型
	 * @param constructorArgs 记录构造函数实参
	 * @param columnPrefix 列前缀
	 * @return 返回 resultType 实体类
	 */
	Object createParameterizedResultObject(ResultSetWrapper rsw, Class<?> resultType,
			List<ResultMapping> constructorMappings, List<Class<?>> constructorArgTypes, List<Object> constructorArgs,
			String columnPrefix) {
		boolean foundValues = false;
		// 遍历 constructorMappings 集合，该过程中会使用 constructorArgTypes 集合记录构造参数类型，
		// 使用 constructorArgs 集合记录构造函数实参
		for (ResultMapping constructorMapping : constructorMappings) {
			// 获取当前构造参数的类型
			final Class<?> parameterType = constructorMapping.getJavaType();
			// 获取当前构造参数对应数据库的column名
			final String column = constructorMapping.getColumn();
			final Object value;
			try {
				if (constructorMapping.getNestedQueryId() != null) {
					// 存在嵌套查询，需要处理该查询，然后才能得到实参
					value = getNestedQueryConstructorValue(rsw.getResultSet(), constructorMapping, columnPrefix);
				} else if (constructorMapping.getNestedResultMapId() != null) {
					// 存在嵌套映射，需要先处理嵌套映射，才能得到实参
					final ResultMap resultMap = configuration.getResultMap(constructorMapping.getNestedResultMapId());
					value = getRowValue(rsw, resultMap, constructorMapping.getColumnPrefix());
				} else {
					// 直接获取该列的值，然后经过 TypeHandler 对象的转换，得到构造函数的实参
					final TypeHandler<?> typeHandler = constructorMapping.getTypeHandler();
					value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(column, columnPrefix));
				}
			} catch (ResultMapException | SQLException e) {
				throw new ExecutorException("Could not process result for mapping: " + constructorMapping, e);
			}
			// 记录当前构造参数类型
			constructorArgTypes.add(parameterType);
			// 记录当前构造参数的实际值
			constructorArgs.add(value);
			foundValues = value != null || foundValues;
		}
		// 通过 ObjectFactory 调用匹配的构造函数，创建结果对象
		return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
	}

	/**
	 * 通过自动映射的方式查找合适的构造方法并创建结果对象
	 * @param rsw mybatis 封装JDBC的Result类
	 * @param resultType 创建的类型
	 * @param constructorArgTypes 记录构造函数中参数类型
	 * @param constructorArgs 记录构造函数中参数的实际值
	 * @param columnPrefix 列前缀
	 * @return resultType 的实例
	 */
	private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType,
			List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix) throws SQLException {
		// 获取该类所有的构造方法
		final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
		// 获取默认的构造方法
		final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);
		if (defaultConstructor != null) {
			return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix,
					defaultConstructor);
		} else {
			// 遍历全部的构造方法
			for (Constructor<?> constructor : constructors) {
				// 查找合适的构造方法
				if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {
					return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, columnPrefix,
							constructor);
				}
			}
		}
		throw new ExecutorException(
				"No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
	}

	private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes,
			List<Object> constructorArgs, String columnPrefix, Constructor<?> constructor) throws SQLException {
		boolean foundValues = false;
		for (int i = 0; i < constructor.getParameterTypes().length; i++) {
			// 获取构造函数的参数类型
			Class<?> parameterType = constructor.getParameterTypes()[i];
			// ResultSet 中的列名
			String columnName = rsw.getColumnNames().get(i);
			// 查找对应的 TypeHandler,并获取该列的值
			TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
			Object value = typeHandler.getResult(rsw.getResultSet(), prependPrefix(columnName, columnPrefix));
			// 记录构造函数的参数类型和参数值
			constructorArgTypes.add(parameterType);
			constructorArgs.add(value);
			foundValues = value != null || foundValues;
		}
		// 使用 ObjectFactory 调用对应的构造方法，创建结果对象
		return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
	}

	/**
	 * 获取默认的构造方法
	 * @param constructors 构造函数方法集合
	 */
	private Constructor<?> findDefaultConstructor(final Constructor<?>[] constructors) {
		if (constructors.length == 1)
			return constructors[0];

		for (final Constructor<?> constructor : constructors) {
			if (constructor.isAnnotationPresent(AutomapConstructor.class)) {
				// 构造方法注解了 @AutomapConstructor
				return constructor;
			}
		}
		return null;
	}

	/**
	 * 判断该构造方法是否合适 ResultSet
	 * <pre>
	 *     合适的构造方法必须满足：参数类型与ResultSet中列所对应的Java类型匹配
	 * </pre>
	 * @param constructor 构造函数方法
	 * @param jdbcTypes ResultSet中所有 jdbcType 类型的集合
	 * @return true-该构造函数可以实例化
	 */
	private boolean allowedConstructorUsingTypeHandlers(final Constructor<?> constructor,
			final List<JdbcType> jdbcTypes) {
		final Class<?>[] parameterTypes = constructor.getParameterTypes();
		if (parameterTypes.length != jdbcTypes.size())
			return false;
		for (int i = 0; i < parameterTypes.length; i++) {
			// 判断 构造函数类型和 resultSet 对应的 jdbcType 是否一致
			if (!typeHandlerRegistry.hasTypeHandler(parameterTypes[i], jdbcTypes.get(i))) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 场景1：结果集只有一列，且存在 TypeHandler 对象可以将该列转换成 resultType 类型的值
	 * <pre>
	 *     先查找相应的 TypeHandler 对象，再使用 TypeHandler 对象将该记录转换成 Java 类型的值
	 * </pre>
	 */
	private Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix)
			throws SQLException {
		final Class<?> resultType = resultMap.getType();
		final String columnName;
		if (!resultMap.getResultMappings().isEmpty()) {
			final List<ResultMapping> resultMappingList = resultMap.getResultMappings();
			final ResultMapping mapping = resultMappingList.get(0);
			columnName = prependPrefix(mapping.getColumn(), columnPrefix);
		} else {
			columnName = rsw.getColumnNames().get(0);
		}
		final TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName);
		return typeHandler.getResult(rsw.getResultSet(), columnName);
	}

	//
	// NESTED QUERY
	//

	/**
	 * 场景：resultMap 配置的构造函数的参数类型和参数值，并选择合适的构造函数创建映射的结果对象
	 * <br/>
	 * 如果其中某个构造参数值是通过嵌套查询获取的，则通过该方法创建该参数值
	 * @param rs JDBC的ResutlSet
	 * @param constructorMapping 构造节点里的 result
	 * @param columnPrefix 列前缀
	 */
	private Object getNestedQueryConstructorValue(ResultSet rs, ResultMapping constructorMapping, String columnPrefix)
			throws SQLException {
		// 获取嵌套查询的 id 以及对应的 MappedStatement 对象
		final String nestedQueryId = constructorMapping.getNestedQueryId();
		final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);
		final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
		// 获取传递给嵌套查询的参数值
		final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, constructorMapping,
				nestedQueryParameterType, columnPrefix);
		Object value = null;
		if (nestedQueryParameterObject != null) {
			// 获取嵌套查询对应的 BoundSql 对象和相应的 CacheKey 对象
			final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
			final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT,
					nestedBoundSql);
			// 获取嵌套查询结果集经过映射后的目标类型
			final Class<?> targetType = constructorMapping.getJavaType();
			// 创建 ResultLoader 对象，并调用 loadResult()方法执行嵌套查询，得到相应的构造方法参数值
			final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
					nestedQueryParameterObject, targetType, key, nestedBoundSql);
			value = resultLoader.loadResult();
		}
		return value;
	}

	/**
	 * 处理嵌套查询
	 * <pre>
	 *     1. 开启延迟加载功能。则创建相应的 ResultLoader 对象并返回 DEFERRED 这个标识对象
	 *     2. 关闭延迟加载功能。则之间执行嵌套查询，并返回结果对象
	 * </pre>
	 * @param rs JDBC 的 ResultSet
	 * @param metaResultObject 外层对象
	 * @param propertyMapping 对应的节点信息
	 * @param lazyLoader 懒加载的ResultLoaderMap
	 * @param columnPrefix 列前缀
	 * @return DEFERRED/嵌套的结果对象
	 */
	private Object getNestedQueryMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping,
			ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
		// 获取嵌套查询的 id 和对应的 MappedStatement 对象
		final String nestedQueryId = propertyMapping.getNestedQueryId();
		final String property = propertyMapping.getProperty();
		final MappedStatement nestedQuery = configuration.getMappedStatement(nestedQueryId);

		// 获取传递给嵌套查询的参数类型和参数值
		final Class<?> nestedQueryParameterType = nestedQuery.getParameterMap().getType();
		final Object nestedQueryParameterObject = prepareParameterForNestedQuery(rs, propertyMapping,
				nestedQueryParameterType, columnPrefix);
		Object value = null;
		if (nestedQueryParameterObject != null) {
			// 获取嵌套查询对应的 BoundSql 对象和相应 CacheKey 对象
			final BoundSql nestedBoundSql = nestedQuery.getBoundSql(nestedQueryParameterObject);
			final CacheKey key = executor.createCacheKey(nestedQuery, nestedQueryParameterObject, RowBounds.DEFAULT,
					nestedBoundSql);
			// 获取嵌套查询结果集经过映射后的目标类型
			final Class<?> targetType = propertyMapping.getJavaType();
			// 检测缓存中是否存在该嵌套查询的结果对象
			if (executor.isCached(nestedQuery, key)) {
				// 创建 DeferredLoad 对象，并通过该 DeferredLoad 对象从缓存中加载结果对象
				executor.deferLoad(nestedQuery, metaResultObject, property, key, targetType);
				// 返回 DEFERRED 标识
				value = DEFERRED;
			} else {
				// 创建嵌套查询相应的 ResultLoader 对象
				final ResultLoader resultLoader = new ResultLoader(configuration, executor, nestedQuery,
						nestedQueryParameterObject, targetType, key, nestedBoundSql);
				if (propertyMapping.isLazy()) {
					// 如果该属性配置了延迟加载，则将其添加到 ResultLoaderMap中,等待真正使用时再执行嵌套查询并得到结果对象
					lazyLoader.addLoader(property, metaResultObject, resultLoader);
					// 返回 DEFERRED 标识
					value = DEFERRED;
				} else {
					// 没有配置延迟加载，则直接调用 ResultLoader.loadResult()方法执行嵌套查询，并映射得到结果对象
					value = resultLoader.loadResult();
				}
			}
		}
		return value;
	}

	private Object prepareParameterForNestedQuery(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType,
			String columnPrefix) throws SQLException {
		if (resultMapping.isCompositeResult()) {
			return prepareCompositeKeyParameter(rs, resultMapping, parameterType, columnPrefix);
		} else {
			return prepareSimpleKeyParameter(rs, resultMapping, parameterType, columnPrefix);
		}
	}

	private Object prepareSimpleKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType,
			String columnPrefix) throws SQLException {
		final TypeHandler<?> typeHandler;
		if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
			typeHandler = typeHandlerRegistry.getTypeHandler(parameterType);
		} else {
			typeHandler = typeHandlerRegistry.getUnknownTypeHandler();
		}
		return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
	}

	private Object prepareCompositeKeyParameter(ResultSet rs, ResultMapping resultMapping, Class<?> parameterType,
			String columnPrefix) throws SQLException {
		final Object parameterObject = instantiateParameterObject(parameterType);
		final MetaObject metaObject = configuration.newMetaObject(parameterObject);
		boolean foundValues = false;
		for (ResultMapping innerResultMapping : resultMapping.getComposites()) {
			final Class<?> propType = metaObject.getSetterType(innerResultMapping.getProperty());
			final TypeHandler<?> typeHandler = typeHandlerRegistry.getTypeHandler(propType);
			final Object propValue = typeHandler.getResult(rs,
					prependPrefix(innerResultMapping.getColumn(), columnPrefix));
			// issue #353 & #560 do not execute nested query if key is null
			if (propValue != null) {
				metaObject.setValue(innerResultMapping.getProperty(), propValue);
				foundValues = true;
			}
		}
		return foundValues ? parameterObject : null;
	}

	private Object instantiateParameterObject(Class<?> parameterType) {
		if (parameterType == null) {
			return new HashMap<>();
		} else if (ParamMap.class.equals(parameterType)) {
			return new HashMap<>(); // issue #649
		} else {
			return objectFactory.create(parameterType);
		}
	}

	/**
	 * 获取最终使用的 ResultMap 对象
	 * <pre>
	 *     根据 ResultMap 对象中记录的 Discriminator 以及参与映射的列值，选择映射操作最终使用的 ResultMap 对象
	 * </pre>
	 * @param rs JDBC的 ResultSet
	 * @param resultMap 映射文件的 ResultMap
	 * @param columnPrefix 列前缀
	 * @return 映射最终使用的 ResultMap
	 */
	public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix)
			throws SQLException {
		// 记录已经处理过的 ResultMap 的Id
		Set<String> pastDiscriminators = new HashSet<>();
		// 获取<resultMap>标签的子标签<discriminator>
		Discriminator discriminator = resultMap.getDiscriminator();
		while (discriminator != null) {
			// 获取记录中对应列的值，其中会使用相应的 TypeHandler 对象将该列值转换成 Java 类型
			final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
			// 根据该列值获取对应的 ResultMap 的 id
			final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));
			if (configuration.hasResultMap(discriminatedMapId)) {
				// 根据上述步骤获取的 id,查找相应的 ResultMap 对象
				resultMap = configuration.getResultMap(discriminatedMapId);
				// 记录当前 Discriminator 对象
				Discriminator lastDiscriminator = discriminator;
				// 获取 ResultMap 对象中的 Discriminator
				discriminator = resultMap.getDiscriminator();
				// 检测 discriminator 是否出现了环形引用
				if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {
					break;
				}
			} else {
				break;
			}
		}
		// 该 ResultMap 对象为映射最终使用的 ResultMap
		return resultMap;
	}

	/**
	 * 获取记录中对应列的值
	 * <pre>
	 *     其中会使用相应的 TypeHandler 对象将该列值转换成 Java 类型
	 * </pre>
	 * @param rs JDBC的 ResultSet
	 * @param discriminator discriminator 节点
	 * @param columnPrefix 列前缀
	 * @return
	 */
	private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix)
			throws SQLException {
		final ResultMapping resultMapping = discriminator.getResultMapping();
		final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();
		return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix));
	}

	private String prependPrefix(String columnName, String prefix) {
		if (columnName == null || columnName.length() == 0 || prefix == null || prefix.length() == 0) {
			return columnName;
		}
		return prefix + columnName;
	}

	//
	// HANDLE NESTED RESULT MAPS
	//

	/**
	 * 嵌套结果映射
	 * <pre>
	 *     1.首先，通过 skipRows() 方法定位指定的记录行。
	 *     2.通过 shouldProcessMoreRows() 方法检测是否能继续映射结果集中剩余的记录行
	 *     3.调用 resolveDiscriminatedRows() 方法，它根据ResultMap中记录的 Discriminator 对象
	 *     	 以及参与映射的记录行中相应的列值，决定映射使用 ResultMap 对象
	 *     4.通过 createRowKey() 方法为该行记录生成 CacheKey,CacheKey 除了作为缓存中的 key 值，在嵌套映射中也作为key唯一标识一个结果对象。
	 *     	 CacheKey是由多部分组成，且由这多个组成部分共同确定两个CacheKey对象是否相等。
	 *     5.CacheKey 查询 DefaultResultSetHandler.nestedResultObject 集合。
	 *     	 DefaultResultSetHandler.nestedResultObject 字段是一个 HashMap 对象。
	 *     	 在除了嵌套映射过程中生成的所有结果对象(包括嵌套映射生成的对象)，都会生成相应的 CacheKey 并保存到该集合中
	 *     6.检测[select]节点中 resultOrdered 属性的配置，该设置仅针对嵌套映射有效。
	 *     		resultOrdered-true：则认为返回一个主结果行时，不会发送步骤5处理第二行记录时那样引用 nestedResultObjects 集合中对象的情况
	 *     							这样就提前释放了 nestedResultObject 集合中的数据，避免在进行嵌套映射出现内存不足的情况。
	 *     7.通过调用 getRowValue() 方法的另一个重载方法，完成当前记录行的映射操作并返回结果对象，其中还会将结果对象添加到 nestedResultObject 集合中。
	 *     8.通过 storeObject() 方法将生成的结果对象保存到 ResultHandler 中
	 * </pre>
	 * @param rsw myBatis封装JDBC的ResultSet
	 * @param resultMap resultMap
	 * @param resultHandler result处理
	 * @param rowBounds 内存分页
	 * @param parentMapping 未处理的Result
	 */
	private void handleRowValuesForNestedResultMap(ResultSetWrapper rsw, ResultMap resultMap,
			ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
		// 创建 DefaultResultContext
		final DefaultResultContext<Object> resultContext = new DefaultResultContext<>();
		ResultSet resultSet = rsw.getResultSet();
		// 步骤1：定位到指定的记录行
		skipRows(resultSet, rowBounds);
		Object rowValue = previousRowValue;
		// 步骤2：检测释放能继续映射结果集中剩余的记录行
		while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
			// 步骤3：通过 resolveDiscriminatedResultMap()方法决定映射使用的 ResultMap 对象
			final ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
			// 步骤4：为该行记录生成 CacheKey
			final CacheKey rowKey = createRowKey(discriminatedResultMap, rsw, null);
			// 步骤5：根据步骤4中生成 CacheKey 查找 nestedResultObjects 集合
			Object partialObject = nestedResultObjects.get(rowKey);
			// issue #577 && #542
			// 步骤6：检测 resultOrdered 属性
			if (mappedStatement.isResultOrdered()) {
				if (partialObject == null && rowValue != null) {
					// 主结果对象发送变化
					// 清空 nestedResultObjects 集合
					nestedResultObjects.clear();
					// 调用 storeObject()方法保存主结果对象(也就是嵌套映射的外层结果对象)
					storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
				}
				// 步骤7：完成该行记录的映射返回结果对象，其中还会将结果添加到 nestedResultObjects 集合中
				rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
			} else {
				// 步骤7：完成该行记录的映射返回结果对象，其中还会将结果添加到 nestedResultObjects 集合中
				rowValue = getRowValue(rsw, discriminatedResultMap, rowKey, null, partialObject);
				if (partialObject == null) {
					// 步骤8：调用 storeObject() 方法保存结果对象
					storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
				}
			}
		}
		// 对 resultOrdered属性为 true 时的特殊处理，调用 storeObject()方法保存结果对象
		if (rowValue != null && mappedStatement.isResultOrdered() && shouldProcessMoreRows(resultContext, rowBounds)) {
			storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
			previousRowValue = null;
		} else if (rowValue != null) {
			previousRowValue = rowValue;
		}
	}

	//
	// GET VALUE FROM ROW FOR NESTED RESULT MAP
	//

	/**
	 * 一行数据进行映射
	 * <pre>
	 *     1. 检测 rowValue (外层对象)是否存在。
	 *     2. 如果外层对象不存在
	 *     		2.1 调用 createResultObject() 方法创建外层对象
	 *     		2.2 通过 shouldApplyAutomaticMappings()方法检测是否开启字段映射。
	 *     				开启：则调用applyAutomaticMappings()方法进行自动映射。
	 *     			注意：shuldApplyAutomaticMappings()方法的第二个参数为 true,表示还有嵌套映射
	 *     		2.3 通过 applyPropertyMappings() 方法处理ResultMap中明确需要进行映射的列
	 *     	到处为止，外层对象以及构建完成
	 *     		2.4 将外层对象添加到 DefaultResultSetHandler.ancestorObject（HashMap<String,Object> 类型） 集合中
	 *     				key: ResultMap的ID
	 *     				value:为外层对象
	 *     		2.5 通过 applyNestedResultMappings()方法处理嵌套映射，其中会将生成的结果对象设置到外层对象的相应属性中。
	 *     		2.6 将外层对象从 ancestorObject 集合中移除
	 *     		2.7 将外层对象添加到 nestedResultObject 集合中，待映射后续记录时使用
	 *     3. 如果外层存在，则表示该外层对象已经由步骤2填充好了
	 *     		3.1 将外层对象添加到 ancestorObject 集合中
	 *     		3.2 通过 applyNestedResultMappings()方法处理嵌套映射，其中会将生成的结果对象设置到外层对象的相应属性中。
	 *     		3.3 将外层对象从 ancestorObjects 集合中移除
	 * </pre>
	 * @param rsw JDBC的ResultSet
	 * @param resultMap resultMap 的节点
	 * @param combinedKey cacheKey
	 * @param columnPrefix 列前缀
	 * @param partialObject 根据CacheKey 查找 nestedResultObjects 的value集合(外层)
	 *
	 * @return
	 * @throws SQLException
	 */
	private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, CacheKey combinedKey, String columnPrefix,
			Object partialObject) throws SQLException {
		final String resultMapId = resultMap.getId();
		Object rowValue = partialObject;
		// 步骤1：检测外层是否存在
		if (rowValue != null) {
			// 根据rowValue 创建 MetaObject
			final MetaObject metaObject = configuration.newMetaObject(rowValue);
			// 步骤3.1：将外层对象添加到 ancestorObject 集合中
			putAncestor(rowValue, resultMapId);
			// 步骤3.2：处理嵌套映射
			applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, false);
			// 步骤3.3：将外层对象从 ancestorObjects 集合中移除
			ancestorObjects.remove(resultMapId);
		} else {
			// 创建封装填充延迟加载的对象
			final ResultLoaderMap lazyLoader = new ResultLoaderMap();
			// 步骤2.1：创建外层POJO对象
			rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
			if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
				final MetaObject metaObject = configuration.newMetaObject(rowValue);
				// 更新 foundValues,其含义与简单映射中同名变量相同。
				// 成功映射任意属性，则 foundValues 为 true,否则 foundValues 为 false
				boolean foundValues = this.useConstructorMappings;
				if (shouldApplyAutomaticMappings(resultMap, true)) {
					// 步骤2.2：自动映射
					foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
				}
				// 步骤2.3：映射 ResultMap 中明确指定的字段
				foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix)
						|| foundValues;
				// 步骤2.4：将外层对象添加到 ancestorObjects 集合中
				putAncestor(rowValue, resultMapId);
				// 步骤2.5：处理嵌套映射
				foundValues = applyNestedResultMappings(rsw, resultMap, metaObject, columnPrefix, combinedKey, true)
						|| foundValues;
				// 步骤2.6：将外层对象从 ancestorObjects 集合中移除
				ancestorObjects.remove(resultMapId);
				foundValues = lazyLoader.size() > 0 || foundValues;
				rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
			}
			if (combinedKey != CacheKey.NULL_CACHE_KEY) {
				// 步骤2.7：将外层对象保存到 nestedResultObjects集合中，待映射后续记录时使用
				nestedResultObjects.put(combinedKey, rowValue);
			}
		}
		return rowValue;
	}

	/**
	 * 将外层对象添加到 ancestorObjects 集合中
	 * @param resultObject 外层POJO实体类
	 * @param resultMapId resultMap的Id属性
	 */
	private void putAncestor(Object resultObject, String resultMapId) {
		ancestorObjects.put(resultMapId, resultObject);
	}

	//
	// NESTED RESULT MAP (JOIN MAPPING)
	//

	/**
	 * 嵌套映射 ResultMap.propertyResultMappings 集合记录的 ResultMapping 对象
	 * <pre>
	 *     1. 获取 ResultMapping.nestedResultMapId 字段值，该值不为空则表示存在相应的嵌套映射要处理。
	 *     2. 通过 resolveDiscriminatedResultMap() 方法确定嵌套映射使用的 ResultMap 对象
	 *     3. 处理循环引用场景
	 *     		如果不存在循环引用的情况，则继续后面的映射流程；
	 *     		如果存在循环引用，则不在创建新的嵌套对象，而是重用之前的对象
	 *     4. 通过 createRowKey()方法为嵌套对象创建 CacheKey。该过程除了根据嵌套对象的信息创建 CacheKey,
	 *     	  	还会与外层对象的 CacheKey 合并，得到全局唯一的 CacheKey 对象
	 *     5. 如果外层对象中用于记录当前嵌套对象的属性为 Collection 类型，且未初始化，
	 *     		则会通过 instantiateCollectionPropertyIfAppropriate()方法初始化该集合对象。
	 *     6. 根据 association,collection 等节点的 notNullColumn 属性，检测结果集中相应列是否为空。
	 *     7. 调用 getRowValue() 方法完成嵌套映射，并生成嵌套对象。
	 *     		嵌套映射可以嵌套多层，也就可以产生多层递归。
	 *     8. 通过 linkObjects() 方法，将步骤7中得到的嵌套对象保存到外层对象中。
	 * </pre>
	 * @param rsw JDBC的ResultSet
	 * @param resultMap resultMap 节点信息
	 * @param metaObject POJO对象
	 * @param parentPrefix 属性前缀
	 * @param parentRowKey 外层的cacheKey
	 * @param newObject
	 * @return
	 */
	private boolean applyNestedResultMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject,
			String parentPrefix, CacheKey parentRowKey, boolean newObject) {
		boolean foundValues = false;
		// 遍历全部 ResultMapping 对象，处理其中的嵌套映射
		for (ResultMapping resultMapping : resultMap.getPropertyResultMappings()) {
			// 获取 ResultMapping.nestedResultMapId
			final String nestedResultMapId = resultMapping.getNestedResultMapId();
			// 步骤1：检测 nestedResultMapId 和 resultSet 两个字段的值
			if (nestedResultMapId != null && resultMapping.getResultSet() == null) {
				try {
					// 获取列前缀
					final String columnPrefix = getColumnPrefix(parentPrefix, resultMapping);
					// 步骤2：确定嵌套映射使用的 ResultMap 对象
					final ResultMap nestedResultMap = getNestedResultMap(rsw.getResultSet(), nestedResultMapId,
							columnPrefix);
					// 步骤3：处理循环引用的情况
					if (resultMapping.getColumnPrefix() == null) {
						// try to fill circular reference only when columnPrefix
						// is not specified for the nested result map (issue #215)
						// 查找嵌套对象在 ancestorObjects 是否已经存在
						Object ancestorObject = ancestorObjects.get(nestedResultMapId);
						if (ancestorObject != null) {// 存在：当前映射的嵌套对象在之前已经进行嵌套，可重用之前映射产生对象
							if (newObject) {
								linkObjects(metaObject, resultMapping, ancestorObject); // issue #385
							}
							// 若是循环引用，则不用执行下面的路径创建新对象，而是重用之前的对象
							continue;
						}
					}
					// 步骤4：为嵌套对象创建 CacheKey 对象
					final CacheKey rowKey = createRowKey(nestedResultMap, rsw, columnPrefix);
					// 嵌套对象的CacheKey 和 外层的CacheKey 合并，得到全局唯一的 CacheKey 对象
					final CacheKey combinedKey = combineKeys(rowKey, parentRowKey);
					// 查找 nestedResultObjects 集合中是否有相同的 Key 的嵌套对象
					Object rowValue = nestedResultObjects.get(combinedKey);
					// nestedResultObjects 是否存在存在嵌套对象。true-存在
					boolean knownValue = rowValue != null;
					// 步骤5：初始化外层对象中 Collection 类型的属性
					instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject); // mandatory
					// 步骤6：根据 notNullColumn 属性检测结果集中列的值是否存在不为空
					if (anyNotNullColumnHasValue(resultMapping, columnPrefix, rsw)) {
						// 步骤7：完成嵌套映射，并生成嵌套对象
						rowValue = getRowValue(rsw, nestedResultMap, combinedKey, columnPrefix, rowValue);
						// 注意：“!knownValue” 这个条件，当嵌套对象已经存在 nestedResultObject 集合中时，说明相关列已经映射成了嵌套对象。
						if (rowValue != null && !knownValue) {
							// 步骤8：将步骤7中得到的嵌套对象保存到外层对象的相应属性中
							linkObjects(metaObject, resultMapping, rowValue);
							foundValues = true;
						}
					}
				} catch (SQLException e) {
					throw new ExecutorException("Error getting nested result map values for '"
							+ resultMapping.getProperty() + "'.  Cause: " + e, e);
				}
			}
		}
		return foundValues;
	}

	private String getColumnPrefix(String parentPrefix, ResultMapping resultMapping) {
		final StringBuilder columnPrefixBuilder = new StringBuilder();
		if (parentPrefix != null) {
			columnPrefixBuilder.append(parentPrefix);
		}
		if (resultMapping.getColumnPrefix() != null) {
			columnPrefixBuilder.append(resultMapping.getColumnPrefix());
		}
		return columnPrefixBuilder.length() == 0 ? null : columnPrefixBuilder.toString().toUpperCase(Locale.ENGLISH);
	}

	/**
	 * 根据 notNullColumn 属性检测结果集中列的值是否存不为空
	 * @param resultMapping
	 * @param columnPrefix
	 * @param rsw
	 * @return true-不为空
	 * @throws SQLException
	 */
	private boolean anyNotNullColumnHasValue(ResultMapping resultMapping, String columnPrefix, ResultSetWrapper rsw)
			throws SQLException {
		// 获取 notNullColumn 属性指定不为空的列名
		Set<String> notNullColumns = resultMapping.getNotNullColumns();
		if (notNullColumns != null && !notNullColumns.isEmpty()) {
			ResultSet rs = rsw.getResultSet();
			for (String column : notNullColumns) {
				rs.getObject(prependPrefix(column, columnPrefix));
				if (!rs.wasNull()) {
					return true;
				}
			}
			return false;
		} else if (columnPrefix != null) {
			for (String columnName : rsw.getColumnNames()) {
				if (columnName.toUpperCase().startsWith(columnPrefix.toUpperCase())) {
					return true;
				}
			}
			return false;
		}
		return true;
	}

	/**
	 * 获取 子节点最终的 ResultMap
	 * @param rs JDBC的ResultSet
	 * @param nestedResultMapId 子节点的ResultMap的Id
	 * @param columnPrefix 列前缀
	 * @return ResultMap 最终的ResultMap
	 */
	private ResultMap getNestedResultMap(ResultSet rs, String nestedResultMapId, String columnPrefix)
			throws SQLException {
		ResultMap nestedResultMap = configuration.getResultMap(nestedResultMapId);
		return resolveDiscriminatedResultMap(rs, nestedResultMap, columnPrefix);
	}

	//
	// UNIQUE RESULT KEY
	//

	/**
	 * 生成CacheKey
	 * <pre>
	 *     1.尝试使用 idArg 节点或 id 节点中定义的列名以及该列在当前记录行中对应的列值组成 CacheKey 对象
	 *     2.如果 ResultMap 中没有定义 idArg 节点或 id 节点，则由 ResultMap 中明确要映射的列名以及它们在当前记录行中对应的列值一起构成 CacheKey 对象
	 *     3.如果经过上述两个步骤后，依然查找不到相关的列名和列值，且 ResultMap.type 属性明确指明了结果对象为 Map 类型，
	 *       则由结果集中所有列名以及该行记录行的所有列值一起构成 CacheKey 对象
	 *     4.如果映射的结果对象不是 Map 类型，则由结果集中未映射的列名以及它们在当前记录行中的对应列值一起构成 CacheKey 对象
	 * </pre>
	 * @param resultMap ResultMap节点
	 * @param rsw JDBC里的ResultSet
	 * @param columnPrefix 列前缀
	 * @return
	 * @throws SQLException
	 */
	private CacheKey createRowKey(ResultMap resultMap, ResultSetWrapper rsw, String columnPrefix) throws SQLException {
		// 创建 CacheKey 对象
		final CacheKey cacheKey = new CacheKey();
		// 将 ResultMap 的 Id 作为 CacheKey 的一部分
		cacheKey.update(resultMap.getId());
		// 查找 ResultMapping 对象集合
		List<ResultMapping> resultMappings = getResultMappingsForRowKey(resultMap);
		if (resultMappings.isEmpty()) {
			// 没有找到任何 ResultMapping
			if (Map.class.isAssignableFrom(resultMap.getType())) {
				// 由结果集中的所有列名以及当前记录行的所有值一起构成 CacheKey 对象
				createRowKeyForMap(rsw, cacheKey);
			} else {
				// 由结果集中未映射的列名以及他们在当前记录行中的对应列值一起构成 CacheKey 对象
				createRowKeyForUnmappedProperties(resultMap, rsw, cacheKey, columnPrefix);
			}
		} else {
			// 由 resultMappings 集合中的列名以及它们在当前记录行中相应的列值一起构成 CacheKey
			createRowKeyForMappedProperties(resultMap, rsw, cacheKey, resultMappings, columnPrefix);
		}
		// 通过上面的查找没有找到任何列参与构成 CacheKey 对象，则返回 NULL_CACHE_KEY 对象
		if (cacheKey.getUpdateCount() < 2) {
			return CacheKey.NULL_CACHE_KEY;
		}
		return cacheKey;
	}

	/**
	 * 嵌套对象的CacheKey 和 外层的CacheKey 合并，得到全局唯一的 CacheKey 对象
	 * @param rowKey 嵌套对象的CacheKey
	 * @param parentRowKey 外层的Cachekey
	 * @return 全局唯一的CacheKey对象
	 */
	private CacheKey combineKeys(CacheKey rowKey, CacheKey parentRowKey) {
		if (rowKey.getUpdateCount() > 1 && parentRowKey.getUpdateCount() > 1) {
			CacheKey combinedKey;
			try {
				combinedKey = rowKey.clone();
			} catch (CloneNotSupportedException e) {
				throw new ExecutorException("Error cloning cache key.  Cause: " + e, e);
			}
			combinedKey.update(parentRowKey);
			return combinedKey;
		}
		return CacheKey.NULL_CACHE_KEY;
	}

	/**
	 * 获取 id* 或是非 id* 的 ResultMapping
	 * @param resultMap
	 * @return
	 */
	private List<ResultMapping> getResultMappingsForRowKey(ResultMap resultMap) {
		// 获取 ResultMap 的 id 和 idArg 节点对应的 ResultMapping 对象
		List<ResultMapping> resultMappings = resultMap.getIdResultMappings();
		if (resultMappings.isEmpty()) {
			// 获取 ResultMap 除 id* 节点之外的 ResultMapping 对象
			resultMappings = resultMap.getPropertyResultMappings();
		}
		return resultMappings;
	}

	/**
	 * 由 resultMappings 集合中的列名以及它们在当前记录行中相应的列值一起构成 CacheKey
	 * @param resultMap resultMap节点
	 * @param rsw JDBC的ResultSet
	 * @param cacheKey 缓存Key
	 * @param resultMappings resultMap里的 result列集合
	 * @param columnPrefix 列前缀
	 */
	private void createRowKeyForMappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey,
			List<ResultMapping> resultMappings, String columnPrefix) throws SQLException {
		// 遍历所有的 resultMappings
		for (ResultMapping resultMapping : resultMappings) {
			// 如果存在嵌套映射，递归调用 createRowKeyForMappedProperties()方法进行处理
			if (resultMapping.getNestedResultMapId() != null && resultMapping.getResultSet() == null) {
				// Issue #392
				// 获取嵌套的 ResultMap 节点信息
				final ResultMap nestedResultMap = configuration.getResultMap(resultMapping.getNestedResultMapId());
				createRowKeyForMappedProperties(nestedResultMap, rsw, cacheKey,
						nestedResultMap.getConstructorResultMappings(),
						prependPrefix(resultMapping.getColumnPrefix(), columnPrefix));
			} else if (resultMapping.getNestedQueryId() == null) { // 不是嵌套映射
				// 获取该列的名称
				final String column = prependPrefix(resultMapping.getColumn(), columnPrefix);
				// 获取该列的TypeHandler对象
				final TypeHandler<?> th = resultMapping.getTypeHandler();
				// 获取映射的列名
				List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
				// Issue #114
				if (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH))) {
					// 获取列值
					final Object value = th.getResult(rsw.getResultSet(), column);
					if (value != null || configuration.isReturnInstanceForEmptyRow()) {
						// 将列名和列值添加到 CacheKey 对象中
						cacheKey.update(column);
						cacheKey.update(value);
					}
				}
			}
		}
	}

	/**
	 * 由结果集中未映射的列名以及他们在当前记录行中的对应列值一起构成 CacheKey 对象
	 * @param resultMap resultMap 节点
	 * @param rsw JDBC的ResultSet
	 * @param cacheKey 缓存key
	 * @param columnPrefix 列前缀
	 */
	private void createRowKeyForUnmappedProperties(ResultMap resultMap, ResultSetWrapper rsw, CacheKey cacheKey,
			String columnPrefix) throws SQLException {
		final MetaClass metaType = MetaClass.forClass(resultMap.getType(), reflectorFactory);
		// 获取 resultMap 未映射的列名
		List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
		// 遍历 resultMap 未映射的列名
		for (String column : unmappedColumnNames) {
			// 列名转换为属性
			String property = column;
			if (columnPrefix != null && !columnPrefix.isEmpty()) {
				// 列名的前缀是否存在columnPrefix列前缀
				if (column.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
					// 去除列前缀并赋值给属性名
					property = column.substring(columnPrefix.length());
				} else {
					continue;
				}
			}
			// 检测该属性是否在pojo类中
			if (metaType.findProperty(property, configuration.isMapUnderscoreToCamelCase()) != null) {
				String value = rsw.getResultSet().getString(column);
				if (value != null) {
					cacheKey.update(column);
					cacheKey.update(value);
				}
			}
		}
	}

	/**
	 * 由结果集中的所有列名以及当前记录行的所有值一起构成 CacheKey 对象
	 */
	private void createRowKeyForMap(ResultSetWrapper rsw, CacheKey cacheKey) throws SQLException {
		// 获取JDBC里面所有的列名
		List<String> columnNames = rsw.getColumnNames();
		for (String columnName : columnNames) {
			// 获取相应的值
			final String value = rsw.getResultSet().getString(columnName);
			if (value != null) {
				cacheKey.update(columnName);
				cacheKey.update(value);
			}
		}
	}

	/**
	 * 将已存在的嵌套对象设置到外层对象的相应属性中
	 * @param metaObject 外层对象
	 * @param resultMapping 列节点信息
	 * @param rowValue 嵌套对象
	 */
	private void linkObjects(MetaObject metaObject, ResultMapping resultMapping, Object rowValue) {
		// 检测外层对象的指定属性是否为 Collection 类型。如果是且未初始化，则初始化该集合属性并返回
		final Object collectionProperty = instantiateCollectionPropertyIfAppropriate(resultMapping, metaObject);
		// 根据属性是否为集合类型，调用 MetaObject 的相应方法，将嵌套对象记录到外层对象的相应属性中
		if (collectionProperty != null) {
			final MetaObject targetMetaObject = configuration.newMetaObject(collectionProperty);
			targetMetaObject.add(rowValue);
		} else {
			// 设置嵌套对象
			metaObject.setValue(resultMapping.getProperty(), rowValue);
		}
	}

	/**
	 * 初始化外层对象中 Collection 类型的属性
	 * <pre>
	 *     1. 判断是否collection类型；不是直接返回null
	 *     2. 判断 resultMapping里的属性(property) 在 metaObject 是否为空
	 *         空：直接创建一个 Collection 对象，并返回
	 *         非空：直接返回 metaObject 对应的值
	 * </pre>
	 * @param resultMapping collection节点信息
	 * @param metaObject
	 * @return
	 */
	private Object instantiateCollectionPropertyIfAppropriate(ResultMapping resultMapping, MetaObject metaObject) {
		final String propertyName = resultMapping.getProperty();
		// 获取 resultMapping 在POJO类型的值
		Object propertyValue = metaObject.getValue(propertyName);
		if (propertyValue == null) {
			Class<?> type = resultMapping.getJavaType();
			if (type == null) {
				type = metaObject.getSetterType(propertyName);
			}
			try {
				// 检测 type 是否Collection类型
				if (objectFactory.isCollection(type)) {
					// 创建 collection 类型
					propertyValue = objectFactory.create(type);
					metaObject.setValue(propertyName, propertyValue);
					return propertyValue;
				}
			} catch (Exception e) {
				throw new ExecutorException("Error instantiating collection property for result '"
						+ resultMapping.getProperty() + "'.  Cause: " + e, e);
			}
		} else if (objectFactory.isCollection(propertyValue.getClass())) {
			return propertyValue;
		}
		return null;
	}

	/**
	 * 检测是否存在 resultType 的 TypeHandler 处理类
	 * @param rsw ResultSetWrapper
	 * @param resultType resultMap 的 type 属性
	 * @return true-存在 TypeHandler 处理类
	 */
	private boolean hasTypeHandlerForResultObject(ResultSetWrapper rsw, Class<?> resultType) {
		if (rsw.getColumnNames().size() == 1) {
			return typeHandlerRegistry.hasTypeHandler(resultType, rsw.getJdbcType(rsw.getColumnNames().get(0)));
		}
		return typeHandlerRegistry.hasTypeHandler(resultType);
	}

}
